/*
 * Copyright (C) 2010-2010 MaoJian Wu
 *
 * Author:
 *	MaoJian Wu
 *
 * Source:
 *	
 *
 * This file is a part of zfspear library.
 *
 *
 */

#include "xmpp_element.h"
#include <QDomDocument>
#include <QXmlStreamWriter>



 XmppElement::XmppElement(const QString &tagName, const QString &ns,QObject* parent):QObject(parent),domDoc_(),parentElement_(NULL),childsList_()  {

     Q_ASSERT(!tagName.isEmpty());
     //SetTagName(tagName);
     //SetXmlns(ns);
     if(ns.isEmpty()) {
       dom_=domDoc_.createElement(tagName);
     } else {
       dom_=domDoc_.createElementNS(ns,tagName);
   }

 }
 XmppElement::~XmppElement() {

    QListIterator<XmppElement*> list(childsList_);
    while (list.hasNext()) {
        XmppElement *e = list.next();
        delete e;

    }
    childsList_.clear();
 }
QString XmppElement::TagName() const {
   return dom_.tagName();
}
QString XmppElement::Prefix(){
   return dom_.prefix();
}
void XmppElement::SetPrefix(const QString& prefix) {
	dom_.setPrefix(prefix);
}

void XmppElement::SetTagName(const QString& name) {
    dom_.setTagName(name);
}
QString XmppElement::Attribute(const QString& name ) const {
    return dom_.attribute(name);
}
void XmppElement::SetAttribute(const QString& name, const QString& value) {
      dom_.setAttribute(name,value);
}

void XmppElement::SetAttribute(const QString& name, qlonglong value) {
    dom_.setAttribute(name,value);
}

void XmppElement::SetAttribute(const QString& name, qulonglong value) {
    dom_.setAttribute(name,value);
}

void XmppElement::SetAttribute(const QString& name, float value) {
    dom_.setAttribute(name,value);
}

void XmppElement::SetAttribute(const QString& name, double value) {
    dom_.setAttribute(name,value);
}

void XmppElement::RemoveAttribute(const QString& name) {
    dom_.removeAttribute(name);
}
bool XmppElement::HasAttribute(const QString& name) const {
    return dom_.hasAttribute(name);
}
XmppElement* XmppElement::ParentXmppElement() {
    return  parentElement_;
}

QList<XmppElement*> XmppElement::SelectElements(const QString& tagName) {
    return QList<XmppElement*>();

}
QList<XmppElement*> XmppElement::SelectElements(const QString& tagName, bool traverseChildren) {
   return QList<XmppElement*>();
}

XmppElement* XmppElement::SelectElement(const QString& tagName) {

    return this->SelectElement_(this,tagName,true);
}

XmppElement* XmppElement::SelectElement(const QString& tagName, bool traverseChildren) {
    return this->SelectElement_(this,tagName,traverseChildren);;
}
QString XmppElement::Xmlns() {
    return dom_.namespaceURI();
}
void XmppElement::SetXmlns(const QString &ns) {

    //dom_.setAttribute("xmlns",ns);
}
void XmppElement::SetValue(const QString &value) {

    for(int i=0;i<dom_.childNodes().count();i++) {
        QDomNode nd = dom_.childNodes().at(i);
        QDomNode::NodeType nodeType = nd.nodeType();
        if (nodeType == QDomNode::TextNode) {
           dom_.removeChild(nd);
        }
    }
    QDomText text=domDoc_.createTextNode(value);
    dom_.appendChild(text);
}
QString XmppElement::Value() {

    return dom_.text();
    //dom_.appendChild(text);
}
QString XmppElement::ToString() {

    //domDoc_.appendChild(dom_);
    //domDoc_.toString();
    QString xmlStr;
    QXmlStreamWriter writer(&xmlStr);
    WriteTree(this,NULL,writer);
    return xmlStr;

}
QByteArray XmppElement::ToByteArray() {

    return ToString().toAscii();

}

void XmppElement::AppendChild(XmppElement *xmppElement) {

    Q_ASSERT(xmppElement!=NULL);
    dom_.appendChild(xmppElement->dom_);

    childsList_.append(xmppElement);
	xmppElement->parentElement_=this;

}
void XmppElement::RemoveChild(XmppElement *xmppElement) {

    Q_ASSERT(xmppElement!=NULL);

    if (childsList_.contains(xmppElement)) {
       dom_.removeChild(xmppElement->dom_);
       childsList_.removeOne(xmppElement);
    }
}
bool XmppElement::IsNull() {
    return dom_.isNull();
}
void XmppElement::WriteTree(XmppElement* element,XmppElement* parent,QXmlStreamWriter& writer) {

    if (element->Prefix().isEmpty()) {
        writer.writeStartElement(element->TagName());
    } else
        writer.writeStartElement(element->Prefix()+ ":" + element->TagName());

    if ( (element->ParentXmppElement()==NULL || element->ParentXmppElement()->Xmlns() != element->Xmlns())
        && !(element->Xmlns().isNull()) && !(element->Xmlns().isEmpty()))  {
        if (element->Prefix().isNull() || element->Prefix().isEmpty())
           writer.writeDefaultNamespace(element->Xmlns());
        else
           writer.writeNamespace( element->Xmlns(), element->Prefix());
    }
    for(int i=0;i<element->dom_.attributes().length();i++) {
        writer.writeAttribute(element->dom_.attributes().item(i).nodeName(),element->dom_.attributes().item(i).nodeValue());
    }
    for(int i=0;i<element->dom_.childNodes().length();i++) {
       QDomNode node=element->dom_.childNodes().item(i);

       if (node.nodeType() == QDomNode::TextNode) {
          QDomText textNode=node.toText();
		  QString a=textNode.data();
          writer.writeCharacters(textNode.data());
       } else
           if (node.nodeType()==QDomNode::CDATASectionNode) {
       }
    }
    int count = element->ChildsCount();

    if (count>0) {
        QList<XmppElement*> list=element->ChildElements();
        QListIterator<XmppElement*> iterator(list);
        while (iterator.hasNext()) {
             XmppElement *e = iterator.next();
             WriteTree(e, NULL, writer);
        }
        writer.writeEndElement();
    } else {
        writer.writeEndElement();
    }

}
QString XmppElement::GetTag(const QString& tagName) {
    XmppElement* tag = this->SelectElement_(this, tagName,false);
    if ( tag != NULL)
       return tag->Value();
    else
       return "";
}
bool XmppElement::HaveTag(const QString& tagName) {

    const XmppElement* tag = this->SelectElement_(this,tagName,false);
    if (tag != NULL)
        return true;
    else
        return false;

}
void XmppElement::SetTag(const QString& tagName) {

    if (!HaveTag(tagName)) {
        XmppElement *e = new  XmppElement(tagName);
        this->AppendChild(e);
    }

}
void XmppElement::SetTag(const QString& tagName,const QString& text) {

    XmppElement *e = this->SelectElement_(this,tagName,false);
    if (e != NULL) {
      e->SetValue(text);

    } else {
        XmppElement *e = new  XmppElement(tagName);
        e->SetValue(text);
        this->AppendChild(e);
    }


}
void XmppElement::AddTag(const QString &tagName) {
    XmppElement *e = new  XmppElement(tagName);
    this->AppendChild(e);
}
void XmppElement::AddTag(const QString &tagName, const QString &text) {
    XmppElement *e = new  XmppElement(tagName);
    e->SetValue(text);
    this->AppendChild(e);
}

bool XmppElement::RemoveTag(const QString& tagName) {

    XmppElement *e = this->SelectElement_(this,tagName,false);
    if (e != NULL) {
         this->RemoveChild(e);
         return true;
     } else
         return false;
}
QList<XmppElement*> XmppElement::ChildElements() {


   /*childsList_.clear();
   for(int i=0;i<dom_.childNodes().count();i++) {
       QDomNode nd = dom_.childNodes().at(i);
       QDomNode::NodeType nodeType = nd.nodeType();
       if (nodeType == QDomNode::ElementNode) {
          QDomElement node = (QDomElement)(dom_.childNodes().at(i));
          XmppElement* e= new XmppElement(node.tagName(),node.namespaceURI());
          e->SetPrefix(node.prefix());
          e->dom_ = node;
          childsList_.append(e);
       }
   }*/
   return childsList_;
}
int XmppElement::ChildsCount()  {
    int i=ChildElements().count();
    return i;
}

XmppElement* XmppElement::SelectElement_(XmppElement *element, QString tagname, bool traverseChildren) {

    XmppElement* e = NULL;
    QList<XmppElement*> eList = element->ChildElements();
    QListIterator<XmppElement*> iterator(eList);
    while( iterator.hasNext()) {
        e=iterator.next();
        if (e->TagName() == tagname)
        {
            return e;
        } else {
            if (traverseChildren) {
                e = SelectElement_(e, tagname, true);
                if (e != NULL)
                    break;
            }
        }
    }

    return e;

}
